package com.arpa.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.core.web.Result;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.wms.cache.GoodsCache;
import com.arpa.wms.domain.consts.CommonConst;
import com.arpa.wms.domain.consts.NumConst;
import com.arpa.wms.domain.dto.ReceiveRegisterDTO;
import com.arpa.wms.domain.entity.*;
import com.arpa.wms.domain.enums.*;
import com.arpa.wms.domain.vo.BatchRuleVO;
import com.arpa.wms.domain.vo.ReceiveItemVO;
import com.arpa.wms.domain.vo.ReceiveRegisterVO;
import com.arpa.wms.mapper.ReceiveRegisterMapper;
import com.arpa.wms.service.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.testng.collections.Lists;

import java.math.BigDecimal;
import java.sql.Struct;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.arpa.wms.domain.consts.NumConst.NUM_ZERO;
import static com.arpa.wms.domain.consts.TipConst.*;

/**
 * <p>
 * 收货登记 服务实现类
 * </p>
 *
 * @author LEO
 * @since 2020-08-04
 */
@Service
public class ReceiveRegisterServiceImpl extends ServiceImpl<ReceiveRegisterMapper, ReceiveRegister> implements IReceiveRegisterService {

    @Autowired
    @Lazy
    private IReceiveService iReceiveService;

    @Autowired
    private IReceiveItemService iReceiveItemService;

    @Autowired
    private IBatchRuleService batchRuleService;

    @Autowired
    private IInventoryService iInventoryService;

    @Autowired
    private IInventoryRecordService iInventoryRecordService;

    @Autowired
    private IContainerService iContainerService;

    @Autowired
    private GoodsCache goodsCache;
    @Autowired
    @Lazy
    private IWmsTaskService taskService;
    @Autowired
    @Lazy
    private IInventoryStatusService inventoryStatusService;

    private final static String RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY = " received_quantity = received_quantity + ";

    /**
     * 保存
     *
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean save(ReceiveRegister entity) {
        entity.setCode(IdUtil.simpleUUID());
        if (StringUtils.isBlank(entity.getCreatedBy())) {
            entity.setCreatedBy(UserUtil.getCode());
        }
        return super.save(entity);
    }

    /**
     * 根据code更新实体
     *
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public int updateByCode(ReceiveRegister entity) {
        if (StringUtils.isBlank(entity.getModifiedBy())) {
            entity.setModifiedBy(UserUtil.getCode());
        }
        return baseMapper.update(entity, new QueryWrapper<ReceiveRegister>().lambda().eq(ReceiveRegister::getCode, entity.getCode()).eq(ReceiveRegister::getGroupCode,UserUtil.getBranchCode()));
    }

    /**
     * 查询列表
     *
     * @param receiveRegisterDTO
     * @return
     */
    @Override
    public List<ReceiveRegisterVO> queryList(ReceiveRegisterDTO receiveRegisterDTO) {
        //排序字段名需要驼峰转数据库下划线类型字段名
        if (StringUtils.isNotEmpty(receiveRegisterDTO.getSortField())) {
            receiveRegisterDTO.setSortField(CommonUtil.camel2Underline(receiveRegisterDTO.getSortField()));
        }
        List<ReceiveRegisterVO> receiveRegisterVOList = baseMapper.queryList(receiveRegisterDTO);
        return receiveRegisterVOList;
    }

    @Override
    public List<ReceiveRegisterVO> queryByInventoryStatus(List<String> statusList) {

        return baseMapper.queryByInventoryStatus(statusList,UserUtil.getBranchCode());
    }

    /**
     * 查询合计,包含总数
     *
     * @param receiveRegisterDTO
     * @return
     */
    @Override
    public ReceiveRegisterVO queryListSum(ReceiveRegisterDTO receiveRegisterDTO) {
        ReceiveRegisterVO receiveRegisterVO = baseMapper.queryListSum(receiveRegisterDTO);
        return receiveRegisterVO;
    }

    /**
     * 查询一个VO
     *
     * @param code
     * @return
     */
    @Override
    public ReceiveRegisterVO getOneByCode(String code) {
        ReceiveRegisterVO receiveRegisterVO = baseMapper.getOneByCode(code,UserUtil.getBranchCode());
        String receiveItemCode = receiveRegisterVO.getReceiveItemCode();
        if (StringUtils.isNotEmpty(receiveItemCode)) {
            BatchRuleVO batchRuleVO = batchRuleService.findVoByreceiveItemCode(receiveItemCode);
            if (batchRuleVO != null) {
                receiveRegisterVO.setBatchRuleVO(batchRuleVO);
            }
        }

        return receiveRegisterVO;
    }

    @Override
    public List<ReceiveRegister> queryAllList(LambdaQueryWrapper<ReceiveRegister> eq) {
        return this.baseMapper.selectList(eq);
    }

    /**
     * pda收货登记
     *
     * @param register
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Result pdaSaveRegister(ReceiveRegister register) {
        String groupCode = UserUtil.getBranchCode();
        WmsTask wmsTask = taskService.getOne(new QueryWrapper<WmsTask>().lambda().eq(WmsTask::getSourceCode, register.getReceiveCode()).eq(WmsTask::getGroupCode,groupCode));
        // pda需要任务排他，但pc允许，所以在PDA保存收货登记时需要自动分配任务，避免其他人操作数据
        if (ObjectUtil.isNotNull(wmsTask)) {
            if (WmsTaskJobStatusEnum.COMPLETED.getValue().equals(wmsTask.getJobStatus().getValue())) {
                throw new ServiceException("该任务已完成，不可再操作！");
            }
            taskService.autoAssign(wmsTask);
        }
        register.setGroupCode(groupCode);
        return this.saveRegister(register);
    }

    /**
     * 保存收货登记信息
     *
     * @param register
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Result saveRegister(ReceiveRegister register) {
        String groupCode = register.getGroupCode();
        WmsTask wmsTask = taskService.getOne(new QueryWrapper<WmsTask>().lambda().eq(WmsTask::getSourceCode, register.getReceiveCode()).eq(WmsTask::getGroupCode,groupCode));
        Receive receive = iReceiveService.getOne(new QueryWrapper<Receive>().lambda().eq(Receive::getCode, register.getReceiveCode()).eq(Receive::getGroupCode,groupCode));
        // 校验收货单状态
        validReceiveStatus(receive);

        // 计算商品的收货数量、基本单位收货数量
        calcQuantity(register);

        // 容器设为被占用, 占用时会判断是否可用（未占用或被本收货单占用）
        occupyContainer(register);

        // 判断收货数量是否超过了计划数量
        ReceiveItem receiveItem = iReceiveItemService.getOne(new QueryWrapper<ReceiveItem>().lambda()
                .eq(ReceiveItem::getGroupCode,groupCode)
                .eq(ReceiveItem::getCode, register.getReceiveItemCode()));
        // 获取明细未登记数量
        BigDecimal itemUnRegisterQuantity = getItemUnRegisterQuantity(receiveItem, register);

        // 将库存加入到临时库存中
//        Inventory tempInventory = saveReceiveTempInventory(register, receive, receiveItem);

        // 查询判断是否有信息相同的登记信息，如果有，则在其基础上更新收货数量
        ReceiveRegister oldRegister = getSameDBRegister(register);

        if (ObjectUtil.isNotNull(oldRegister)) {
            this.update(new UpdateWrapper<ReceiveRegister>().lambda().eq(ReceiveRegister::getCode, oldRegister.getCode())
                    .setSql(RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY + register.getReceivedQuantity()));
            //设置此项的目的是用来判断临时库存用的
            register.setCode(oldRegister.getCode());
        } else {
            // 保存收货登记信息
            register.setBasicQuantity(register.getReceivedQuantity().multiply(register.getUnitConvertQuantity()));
            register.setStatus(ReceiveItemStatusEnum.REGISTER_FINISH.getValue());
            //由于再次进行收货登记的时候，传入的参数带有上架数量，所以在此将上架数量置零
            register.setInboundQuantity(BigDecimal.ZERO);
            save(register);
        }

        // 将库存加入到临时库存中
        Inventory tempInventory = saveReceiveTempInventory(register, receive, receiveItem);
        //更新收货登记的临时库存
        this.update(new LambdaUpdateWrapper<ReceiveRegister>().eq(ReceiveRegister::getCode,register.getCode())
                .set(ReceiveRegister::getTempInventoryCode,tempInventory.getCode()));

        // 记录库存变动日志
        iInventoryRecordService.insertRecord(tempInventory, receive.getCode(), register.getReceivedQuantity(), InventoryRecordTypeEnum.RECEIVE.getValue());

        // 更新收货明细收货数量 如果计划数量等于收货数量 把收货单明细状态置为已收货,反之，状态置为收货中
        String itemStatus;
        if (itemUnRegisterQuantity.compareTo(BigDecimal.ZERO) == 0) {
            itemStatus = ReceiveItemStatusEnum.FINISH_RECEIVE.getValue();
        } else {
            itemStatus = ReceiveItemStatusEnum.PART_RECEIVE.getValue();
        }
        iReceiveItemService.update(new UpdateWrapper<ReceiveItem>().lambda().eq(ReceiveItem::getCode, register.getReceiveItemCode())
                .setSql(RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY + register.getReceivedQuantity()).set(ReceiveItem::getStatus, itemStatus));

        // 判断收货单计划数量与收货登记数量，如果收货数量==计划数量，那就直接完成收货
        List<ReceiveRegister> allRegister = this.list(new QueryWrapper<ReceiveRegister>().lambda().eq(ReceiveRegister::getReceiveCode, register.getReceiveCode())
                .eq(ReceiveRegister::getGroupCode, register.getGroupCode()));
        BigDecimal registerQuantity = allRegister.stream().map(ReceiveRegister::getReceivedQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (registerQuantity.compareTo(receive.getTotalQuantity()) == 0) {
            iReceiveService.update(new UpdateWrapper<Receive>().lambda().eq(Receive::getCode, register.getReceiveCode())
                    .setSql(RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY + register.getReceivedQuantity()));
            iReceiveService.finishReceiveInfo(receive);

            /*// 如果有任务 更新收货任务状态为完成状态
            if (ObjectUtil.isNotNull(wmsTask) && !WmsTaskJobStatusEnum.COMPLETED.equals(wmsTask.getJobStatus())) {
                taskService.update(new UpdateWrapper<WmsTask>().lambda().eq(WmsTask::getCode, wmsTask.getCode())
                        .setSql("job_quantity = job_quantity + " + register.getReceivedQuantity())
                        .set(WmsTask::getJobStatus, WmsTaskJobStatusEnum.COMPLETED.getValue()));
            }*/
        } else {
            // 更新收货单主表收货数量
            iReceiveService.update(new UpdateWrapper<Receive>().lambda().eq(Receive::getCode, register.getReceiveCode())
                    .eq(Receive::getGroupCode, register.getGroupCode())
                    .set(Receive::getStatus, ReceiveStatusEnum.PART_RECEIVE.getValue())
                    .setSql(RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY + register.getReceivedQuantity()));

            // 如果有任务 更新任务作业数量、作业人
            if (ObjectUtil.isNotNull(wmsTask) && !WmsTaskJobStatusEnum.COMPLETED.equals(wmsTask.getJobStatus())) {
                taskService.update(new UpdateWrapper<WmsTask>().lambda().eq(WmsTask::getCode, wmsTask.getCode())
                        .setSql("job_quantity = job_quantity + " + register.getReceivedQuantity())
                        .set(WmsTask::getJobStatus, WmsTaskJobStatusEnum.WORKING.getValue()));
            }
        }
        return Result.ok();
    }

    /**
     * 根据上架单code更新批号、存货日期
     *
     * @param putawayCode
     * @return
     */
    @Override
    public int updateInventoryInfoByPutawayCode(String putawayCode,String groupCode) {
        return this.baseMapper.updateInventoryInfoByPutawayCode(putawayCode,groupCode);
    }

    /**
     * 收货登记 整单确认
     *
     * @param register
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Result wholeConfirm(ReceiveRegister register) {
        String groupCode = UserUtil.getBranchCode();
        register.setGroupCode(groupCode);
        Receive receive = iReceiveService.getOne(new QueryWrapper<Receive>().lambda().eq(Receive::getCode, register.getReceiveCode()).eq(Receive::getGroupCode,groupCode));
        // 校验收货单状态
        validReceiveStatus(receive);
        // 计算商品的收货数量、基本单位收货数量
        calcQuantity(register);

        // 容器设为被占用, 占用时会判断是否可用（未占用或被本收货单占用）
        occupyContainer(register);

        if (register.getReceivedQuantity().compareTo(BigDecimal.ZERO) > 0) {
            // 判断收货数量是否超过了计划数量
            ReceiveItem receiveItem = iReceiveItemService.getOne(new QueryWrapper<ReceiveItem>().lambda()
                    .eq(ReceiveItem::getGroupCode,groupCode)
                    .eq(ReceiveItem::getCode, register.getReceiveItemCode())
                    .eq(ReceiveItem::getDeleted, NUM_ZERO));
            List<ReceiveRegister> receiveRegisterList = this.list(new QueryWrapper<ReceiveRegister>().lambda()
                    .eq(ReceiveRegister::getReceiveItemCode, register.getReceiveItemCode())
                    .eq(ReceiveRegister::getGroupCode,groupCode)
                    .eq(ReceiveRegister::getDeleted, NUM_ZERO.intValue()));

            BigDecimal totalQuantity = receiveItem.getPlanQuantity();
            BigDecimal sumQuantity = receiveRegisterList.stream().map(ReceiveRegister::getReceivedQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 再添加上本次收货数量
            sumQuantity = sumQuantity.add(register.getReceivedQuantity());

            if (sumQuantity.subtract(totalQuantity).compareTo(BigDecimal.ZERO) > 0) {
                // 收货数量大于原计划的收货数量
                throw new ServiceException(RECEIVE_NUM + MORE_THAN + PLAN_QUANTITY);
            }

            // 将库存加入到临时库存中
            Inventory tempInventory = saveReceiveTempInventory(register, receive, receiveItem);

            // 查询判断是否有信息相同的登记信息，如果有，则在其基础上更新收货数量
            ReceiveRegister oldRegister = getSameDBRegister(register);

            if (ObjectUtil.isNotNull(oldRegister)) {
                this.update(new UpdateWrapper<ReceiveRegister>().lambda().eq(ReceiveRegister::getCode, oldRegister.getCode())
                        .eq(ReceiveRegister::getGroupCode,groupCode)
                        .setSql(RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY + register.getReceivedQuantity()));
            } else {
                // 保存收货登记信息
                register.setBasicQuantity(register.getReceivedQuantity().multiply(register.getUnitConvertQuantity()));
                register.setTempInventoryCode(tempInventory.getCode());
                save(register);
            }

            // 记录库存变动日志
            iInventoryRecordService.insertRecord(tempInventory, receive.getCode(), register.getReceivedQuantity(), InventoryRecordTypeEnum.RECEIVE.getValue());

            // 更新收货明细收货数量
            iReceiveItemService.update(new UpdateWrapper<ReceiveItem>().lambda().eq(ReceiveItem::getCode, register.getReceiveItemCode())
                    .eq(ReceiveItem::getGroupCode,groupCode)
                    .setSql(RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY + register.getReceivedQuantity())
                    .set(ReceiveItem::getStatus, ReceiveItemStatusEnum.FINISH_RECEIVE.getValue()));

            iReceiveService.update(new UpdateWrapper<Receive>().lambda().eq(Receive::getCode, register.getReceiveCode())
                    .eq(Receive::getGroupCode,groupCode)
                    .setSql(RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY + register.getReceivedQuantity()));

        } else {
            // 如果什么都不填，且之前的收货数量为0，则不允许完成收货
            if (receive.getReceivedQuantity().compareTo(BigDecimal.ZERO) == 0){
                throw new ServiceException("当前任务未进行收货操作，不能整单确认");
            }

            // 更新收货明细状态
            List<ReceiveItem> receiveItemList = iReceiveItemService.list(new QueryWrapper<ReceiveItem>().lambda().eq(ReceiveItem::getReceiveCode, receive.getCode())
                    .eq(ReceiveItem::getGroupCode,groupCode)
                    .eq(ReceiveItem::getDeleted, NUM_ZERO));
            receiveItemList.forEach(item -> item.setStatus(ReceiveItemStatusEnum.FINISH_RECEIVE.getValue()));
            iReceiveItemService.saveOrUpdateBatch(receiveItemList);
        }
        iReceiveService.finishReceiveInfo(receive);

        // 如果有任务 更新收货任务状态为完成状态
        WmsTask wmsTask = taskService.getOne(new QueryWrapper<WmsTask>().lambda().eq(WmsTask::getSourceCode, register.getReceiveCode()).eq(WmsTask::getGroupCode,groupCode));
        if (ObjectUtil.isNotNull(wmsTask) && WmsTaskJobStatusEnum.COMPLETED.getValue().equals(wmsTask.getJobStatus())) {
            taskService.update(new UpdateWrapper<WmsTask>().lambda().eq(WmsTask::getCode, wmsTask.getCode())
                    .eq(WmsTask::getGroupCode,groupCode)
                    .setSql("job_quantity = job_quantity + " + register.getReceivedQuantity())
                    .set(WmsTask::getJobStatus, WmsTaskJobStatusEnum.COMPLETED.getValue())
                    .set(WmsTask::getOperatorBy, register.getOperatorBy())
                    .set(WmsTask::getOperatorName, register.getOperatorName()));
        }

        return Result.ok();
    }

    /**
     * 统计上架明细单上架数量，更新指定收货确认单的上架数量
     *
     * @param receiveRegisterCode
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void refreshPutawayQuantity(String receiveRegisterCode) {
        this.baseMapper.refreshPutawayQuantity(receiveRegisterCode,UserUtil.getBranchCode());
    }

    /**
     * 统计上架明细单上架数量，更新指定收货确认单的上架和入库数量
     *
     * @param receiveRegisterCode
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void refreshPutawayAndInboundQuantity(String receiveRegisterCode) {
        this.baseMapper.refreshPutawayAndInboundQuantity(receiveRegisterCode,UserUtil.getBranchCode());
    }

    /**
     * 计算收货数量、收货基本单位数量；
     * 在PC端，会传递收货数量，但基本单位收货数量需要计算；
     * 在PDA端，会传递基本单位收货数量，需要根据转换量计算出收货数量；
     * 同时可能存在小数，所以需要通过商品的精度四舍五入
     *
     * @param register
     */
    public void calcQuantity(ReceiveRegister register) {
        Map<String, Object> goodsMap = goodsCache.get(register.getGoodsCode());
        BigDecimal basicQuantity = BigDecimal.ZERO;
        BigDecimal receivedQuantity = BigDecimal.ZERO;
        if (goodsMap != null) {
            int unitPrecision = new BigDecimal(goodsMap.get("unitPrecision").toString()).intValue();
            if (register.getBasicQuantity() == null) {
                receivedQuantity = register.getReceivedQuantity();
                basicQuantity = receivedQuantity.multiply(register.getUnitConvertQuantity());
                basicQuantity = basicQuantity.setScale(unitPrecision, BigDecimal.ROUND_HALF_UP);
            } else if (register.getReceivedQuantity() == null) {
                basicQuantity = register.getBasicQuantity();
                receivedQuantity = basicQuantity.divide(register.getUnitConvertQuantity(), unitPrecision, BigDecimal.ROUND_HALF_UP).setScale(unitPrecision, BigDecimal.ROUND_HALF_UP);
            }
        } else {
            // 商品缓存没有的情况，就只能根据前端传递的数据计算了
            receivedQuantity = register.getReceivedQuantity();
            basicQuantity = register.getBasicQuantity();
        }

        register.setBasicQuantity(basicQuantity);
        register.setReceivedQuantity(receivedQuantity);
    }


    /**
     * 收货登记时，将商品放到临时库存中
     *
     * @param register
     * @param receive
     * @param receiveItem
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    public Inventory saveReceiveTempInventory(ReceiveRegister register, Receive receive, ReceiveItem receiveItem) {
        // 判断是否有相同的临时库存，如果有，则在其基础上增加数量，如果没有，则新增一条
        Inventory inventory = iInventoryService.hasSameReceiveTempInventory(register, receive);
        if (inventory == null) {
            inventory = iInventoryService.saveReceiveTempInventory(register, receive, receiveItem);
        } else {
            // 增加量需要根据收货数量*基本单位转换量计算
            BigDecimal changeQuantity = register.getReceivedQuantity().multiply(receiveItem.getUnitConvertQuantity());
            iInventoryService.adjustQuantity(inventory.getCode(), changeQuantity);
        }

        return inventory;
    }

    /**
     * 根据register信息判断数据库中是否有相同数据
     * @param register
     * @return
     */
    @Override
    public ReceiveRegister getSameDBRegister(ReceiveRegister register) {
        ReceiveRegister sameOne = getOne(new QueryWrapper<ReceiveRegister>().lambda()
                .eq(ReceiveRegister::getReceiveItemCode, register.getReceiveItemCode())
                .eq(ReceiveRegister::getDeleted, 0)
                .eq(ReceiveRegister::getGoodsStatus, register.getGoodsStatus())
                .isNull(ObjectUtil.isNull(register.getReceiveLot()), ReceiveRegister::getReceiveLot)
                .eq(ObjectUtil.isNotNull(register.getReceiveLot()), ReceiveRegister::getReceiveLot, register.getReceiveLot())
                .isNull(ObjectUtil.isNull(register.getPutawayCode()), ReceiveRegister::getPutawayCode)
                .eq(ObjectUtil.isNotNull(register.getPutawayCode()), ReceiveRegister::getPutawayCode, register.getPutawayCode())
                .isNull(ObjectUtil.isNull(register.getGmtManufacture()), ReceiveRegister::getGmtManufacture)
                .eq(ObjectUtil.isNotNull(register.getGmtManufacture()), ReceiveRegister::getGmtManufacture, register.getGmtManufacture())
                .isNull(ObjectUtil.isNull(register.getGmtExpire()), ReceiveRegister::getGmtExpire)
                .eq(ObjectUtil.isNotNull(register.getGmtExpire()), ReceiveRegister::getGmtExpire, register.getGmtExpire())
                .isNull(ObjectUtil.isNull(register.getSupplier()), ReceiveRegister::getSupplier)
                .eq(ObjectUtil.isNotNull(register.getSupplier()), ReceiveRegister::getSupplier, register.getSupplier())
                .isNull(ObjectUtil.isNull(register.getSerialNumber()), ReceiveRegister::getSerialNumber)
                .eq(ObjectUtil.isNotNull(register.getSerialNumber()), ReceiveRegister::getSerialNumber, register.getSerialNumber())
                .isNull(ObjectUtil.isNull(register.getExtendOne()), ReceiveRegister::getExtendOne)
                .eq(ObjectUtil.isNotNull(register.getExtendOne()), ReceiveRegister::getExtendOne, register.getExtendOne())
                .isNull(ObjectUtil.isNull(register.getExtendTwo()), ReceiveRegister::getExtendTwo)
                .eq(ObjectUtil.isNotNull(register.getExtendTwo()), ReceiveRegister::getExtendTwo, register.getExtendTwo())
                .isNull(ObjectUtil.isNull(register.getExtendThree()), ReceiveRegister::getExtendThree)
                .eq(ObjectUtil.isNotNull(register.getExtendThree()), ReceiveRegister::getExtendThree, register.getExtendThree())
                .isNull(ObjectUtil.isNull(register.getExtendFour()), ReceiveRegister::getExtendFour)
                .eq(ObjectUtil.isNotNull(register.getExtendFour()), ReceiveRegister::getExtendFour, register.getExtendFour())
                .isNull(ObjectUtil.isNull(register.getExtendFive()), ReceiveRegister::getExtendFive)
                .eq(ObjectUtil.isNotNull(register.getExtendFive()), ReceiveRegister::getExtendFive, register.getExtendFive())
                .isNull(ObjectUtil.isNull(register.getExtendSix()), ReceiveRegister::getExtendSix)
                .eq(ObjectUtil.isNotNull(register.getExtendSix()), ReceiveRegister::getExtendSix, register.getExtendSix())
                .eq(ReceiveRegister::getContainerBarCode, StrUtil.blankToDefault(register.getContainerBarCode(), StrUtil.EMPTY))
        );
        return sameOne;
    }

    /**
     * 校验收货单状态
     * @param receive
     */
    @Transactional(rollbackFor = {Exception.class})
    public void validReceiveStatus(Receive receive) {
        if (ObjectUtil.isNull(receive)) {
            throw new ServiceException("该收货单不存在！");
        }
        if (ReceiveStatusEnum.FINISH_RECEIVE.getValue().equals(receive.getStatus())) {
            throw new ServiceException("该收货单已收货完成，不可再收货！");
        }
        if (ReceiveStatusEnum.CANCEL.getValue().equals(receive.getStatus())) {
            throw new ServiceException("该收货单已作废，不可再收货！");
        }
    }

    /**
     * 占用容器
     * @param register
     */
    @Transactional(rollbackFor = {Exception.class})
    public void occupyContainer(ReceiveRegister register) {
        if (StrUtil.isNotBlank(register.getContainerBarCode())) {
            Result occupyResult = iContainerService.occupyContainer(register.getReceiveCode(), register.getContainerBarCode(),register.getGroupCode());
            Container container = (Container) occupyResult.get("data");
            register.setContainerType(container.getType());
        }
    }

    /**
     * 计算明细中未确认的收货数量
     * @param receiveItem
     * @param register
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    public BigDecimal getItemUnRegisterQuantity(ReceiveItem receiveItem, ReceiveRegister register) {
        if (register.getReceivedQuantity().compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("收货数量需要大于0");
        }

        BigDecimal itemRegisterQuantity;
        List<ReceiveRegister> receiveRegisterList = this.list(new QueryWrapper<ReceiveRegister>().lambda()
                .eq(ReceiveRegister::getGroupCode,UserUtil.getBranchCode())
                .eq(ReceiveRegister::getReceiveItemCode, register.getReceiveItemCode()));

        BigDecimal itemTotalQuantity = receiveItem.getPlanQuantity();
        itemRegisterQuantity = receiveRegisterList.stream().map(ReceiveRegister::getReceivedQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 再添加上本次收货数量
        itemRegisterQuantity = itemRegisterQuantity.add(register.getReceivedQuantity());

        if (itemRegisterQuantity.compareTo(itemTotalQuantity) > 0) {
            // 收货数量大于原计划的收货数量
            throw new ServiceException(RECEIVE_NUM + MORE_THAN + PLAN_QUANTITY);
        }

        return itemTotalQuantity.subtract(itemRegisterQuantity);
    }

    /**
     * 一键收货
     * @param receiveItemVOS
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Result batchCreate(List<ReceiveItemVO> receiveItemVOS){
        int numLimit = 20;
        if (IterUtil.isEmpty(receiveItemVOS)) {
            throw new ServiceException("请选择收货登记信息");
        }
        if (receiveItemVOS.size() > numLimit) {
            throw new ServiceException("一次收货最多选择20条收货登记信息");
        }
        //收货批次号判断，含有收货批次信息且里面的12条内容有勾选的，则不能通过一键收货进行收货
        receiveItemVOS.stream().forEach(e -> {
            BatchRuleVO batchRuleVO = batchRuleService.findVoByreceiveItemCode(e.getCode());
            if(ObjectUtil.isNotNull(batchRuleVO)) {
                //判断是否勾选批次规则
                boolean checked = checkBatchRule(batchRuleVO);
                if (checked) {
                    throw new ServiceException("商品【" + e.getGoodsName() + "】的批次规则信息已维护扩展内容，不允许一键收货");
                }
            }
        });
        //receiveItemVOS转换为收货登记receiveRegisterList
        List<ReceiveRegister> receiveRegisterList = constructReceiveRegisterList(receiveItemVOS);
        String groupCode = UserUtil.getBranchCode();
        String receiveCode = receiveRegisterList.get(NUM_ZERO).getReceiveCode();
        WmsTask wmsTask = taskService.getOne(new QueryWrapper<WmsTask>().lambda().eq(WmsTask::getSourceCode, receiveCode).eq(WmsTask::getGroupCode,groupCode));
        Receive receive = iReceiveService.getOne(new QueryWrapper<Receive>().lambda().eq(Receive::getCode, receiveCode).eq(Receive::getGroupCode,groupCode));
        // 校验收货单状态
        validReceiveStatus(receive);
        //获取货品状态
        InventoryStatus inventoryStatus = getInventoryStatus(receive);
        //如果选中的收货单已经进行了收货，则无法通过一键收货进行收货
        List<String> goodsCodeList = receiveRegisterList.stream().map(ReceiveRegister::getGoodsCode).collect(Collectors.toList());
        //查询当前收货单下已收货过的收货登记信息
        List<ReceiveRegister> receivedGoodsCodeList = this.list(new LambdaQueryWrapper<ReceiveRegister>()
                .eq(ReceiveRegister::getReceiveCode, receiveCode)
                .eq(ReceiveRegister::getGroupCode, groupCode)
                .in(ReceiveRegister::getGoodsCode,goodsCodeList)
        );
        if (IterUtil.isNotEmpty(receivedGoodsCodeList)) {
            StringBuilder sb = new StringBuilder();
            sb.append("商品【");
            receivedGoodsCodeList.stream().forEach(e -> {
                sb.append(goodsCache.getObj(e.getGoodsCode()).getName());
                sb.append("  ");
            });
            sb.append("】已经进行了收货登记，无法进行一键收货");
            throw new ServiceException(sb.toString());
        }
        receiveRegisterList.stream().forEach(e -> {
            e.setCode(IdUtil.simpleUUID());
            e.setReceivedQuantity(e.getPlanQuantity());
            e.setStatus(ReceiveItemStatusEnum.REGISTER_FINISH.getValue());
            e.setGroupCode(groupCode);
            e.setGoodsStatus(inventoryStatus.getCode());
            e.setGoodsStatusName(inventoryStatus.getName());
        });
        //批量生成收获登记单
        saveBatch(receiveRegisterList);

        //批量生成临时库存
        List<String> receiveitemCodes = receiveRegisterList.stream().map(ReceiveRegister::getReceiveItemCode).collect(Collectors.toList());
        List<ReceiveItem> receiveItems = iReceiveItemService.list(new LambdaQueryWrapper<ReceiveItem>().in(ReceiveItem::getCode, receiveitemCodes));
        List<Inventory> inventoryList = iInventoryService.batchGenReceiveTempInventory(receiveRegisterList,receiveItems,receive);
        iInventoryService.saveBatch(inventoryList);
        //批量更新收货登记库存code
        Map<String, Inventory> inventoryMap = inventoryList.stream().collect(Collectors.toMap(Inventory::getTempRegisterCode, e -> e));
        receiveRegisterList.stream().forEach(e -> {
            //更新收货登记库存code
            this.update(new LambdaUpdateWrapper<ReceiveRegister>()
                    .eq(ReceiveRegister::getCode, e.getCode())
                    .set(ReceiveRegister::getTempInventoryCode, MapUtil.get(inventoryMap, e.getCode(), Inventory.class).getCode())
            );
            //更新收货明细数量及状态
            iReceiveItemService.update(new LambdaUpdateWrapper<ReceiveItem>()
                    .eq(ReceiveItem::getCode, e.getReceiveItemCode())
                    .setSql("received_quantity = plan_quantity")
                    .set(ReceiveItem::getStatus, ReceiveItemStatusEnum.FINISH_RECEIVE.getValue())
            );
            // 记录库存变动日志
            iInventoryRecordService.insertRecord(MapUtil.get(inventoryMap, e.getCode(), Inventory.class), receiveCode, e.getReceivedQuantity(), InventoryRecordTypeEnum.RECEIVE.getValue());
        });

        //本次收货数量
        BigDecimal receiveQuantity = receiveRegisterList.stream().map(ReceiveRegister::getReceivedQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 判断收货单计划数量与收货登记数量，如果收货数量==计划数量，那就直接完成收货
        List<ReceiveRegister> allRegister = this.list(new QueryWrapper<ReceiveRegister>().lambda().eq(ReceiveRegister::getReceiveCode, receiveCode)
                .eq(ReceiveRegister::getGroupCode, groupCode));
        BigDecimal registerQuantity = allRegister.stream().map(ReceiveRegister::getReceivedQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (registerQuantity.compareTo(receive.getTotalQuantity()) == 0) {
            iReceiveService.update(new UpdateWrapper<Receive>().lambda().eq(Receive::getCode, receiveCode)
                    .setSql(RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY + receiveQuantity));
            iReceiveService.finishReceiveInfo(receive);

        } else {
            // 更新收货单主表收货数量
            iReceiveService.update(new UpdateWrapper<Receive>().lambda().eq(Receive::getCode, receiveCode)
                    .eq(Receive::getGroupCode, groupCode)
                    .set(Receive::getStatus, ReceiveStatusEnum.PART_RECEIVE.getValue())
                    .setSql(RECEIVED_QUANTITY_EQUALS_RECEIVED_QUANTITY + receiveQuantity));

            // 如果有任务 更新任务作业数量、作业人
            if (ObjectUtil.isNotNull(wmsTask) && !WmsTaskJobStatusEnum.COMPLETED.equals(wmsTask.getJobStatus())) {
                taskService.update(new UpdateWrapper<WmsTask>().lambda().eq(WmsTask::getCode, wmsTask.getCode())
                        .setSql("job_quantity = job_quantity + " + receiveQuantity)
                        .set(WmsTask::getJobStatus, WmsTaskJobStatusEnum.WORKING.getValue()));
            }
        }
        return Result.ok();

    }

    private boolean checkBatchRule(BatchRuleVO batchRuleVO) {
        if (batchRuleVO.getLot() == 1) {
            return true;
        }
        if (batchRuleVO.getGmtManufacture() == 1) {
            return true;
        }
        if (batchRuleVO.getGmtExpire() == 1) {
            return true;
        }
        if (batchRuleVO.getGmtStock() == 1) {
            return true;
        }
        if (batchRuleVO.getSupplier() == 1) {
            return true;
        }
        if (batchRuleVO.getSerialNumber() == 1) {
            return true;
        }
        if (batchRuleVO.getExtendOne() == 1) {
            return true;
        }
        if (batchRuleVO.getExtendTwo() == 1) {
            return true;
        }
        if (batchRuleVO.getExtendThree() == 1) {
            return true;
        }
        if (batchRuleVO.getExtendFour() == 1) {
            return true;
        }
        if (batchRuleVO.getExtendFive() == 1) {
            return true;
        }
        if (batchRuleVO.getExtendSix() == 1) {
            return true;
        }
        return false;
    }

    private List<ReceiveRegister> constructReceiveRegisterList(List<ReceiveItemVO> receiveItemVOS) {
        List<ReceiveRegister> receiveRegisters = Lists.newArrayList();
        receiveItemVOS.stream().forEach(e -> {
            ReceiveRegister receiveRegister = new ReceiveRegister();
            BeanUtil.copyProperties(e,receiveRegister);
            receiveRegister.setId(StrUtil.EMPTY);
            receiveRegister.setCode(StrUtil.EMPTY);
            receiveRegister.setReceiveItemCode(e.getCode());
            receiveRegisters.add(receiveRegister);
        });
        return receiveRegisters;
    }

    private InventoryStatus getInventoryStatus (Receive receive) {
        InventoryStatus inventoryStatus ;
        List<InventoryStatus> inventoryStatuses = inventoryStatusService.list(new QueryWrapper<InventoryStatus>().lambda()
                .eq(InventoryStatus::getDeleted, "0").eq(InventoryStatus::getStatus, StatusEnum.ACTIVE.getValue())
                .eq(InventoryStatus::getShipmentCode, receive.getShipmentCode()).eq(InventoryStatus::getGroupCode,receive.getGroupCode()));
        if (IterUtil.isEmpty(inventoryStatuses)) {
            throw new ServiceException("当前入驻商【" + receive.getShipmentName() + "】货品状态为空，请在基础信息里进行维护");
        }
        List<InventoryStatus> usefulInventoryStatus = inventoryStatuses.stream()
                .filter(e -> StrUtil.equalsAny(e.getName(), "合格", "有效", "正常")).collect(Collectors.toList());

        if (IterUtil.isNotEmpty(usefulInventoryStatus)) {
            inventoryStatus = usefulInventoryStatus.get(NUM_ZERO);
        } else {
            inventoryStatus = inventoryStatuses.get(NUM_ZERO);
        }
        return inventoryStatus;
    }
}
